#include "wifi_sta_connect.h"
#include "soc_osal.h"

#define CODE_LOG "[WIFI_STA]"
#define WIFI_NOT_AVALLIABLE 0
#define WIFI_SCAN_AP_LIMIT 64
#define WIFI_GET_IP_MAX_COUNT 300

static char WiFi_Sta_SSID[WIFI_MAX_SSID_LEN] = {0};
static char WiFi_Sta_KEY[WIFI_MAX_KEY_LEN] = {0};

static td_void wifi_scan_state_changed(td_s32 state, td_s32 size);
static td_void wifi_connection_changed(td_s32 state, const wifi_linked_info_stru *info, td_s32 reason_code);

wifi_event_stru wifi_event_cb = {
	.wifi_event_connection_changed = wifi_connection_changed,
	.wifi_event_scan_state_changed = wifi_scan_state_changed,
};

static wifi_sta_event_cb_t g_wifi_sta_event_cb = NULL; // wifi-sta msg queue
void wifi_sta_Handletask(void *arg);

enum
{
	WIFI_STA_SAMPLE_INIT = 0,	  /* 0:初始态 */
	WIFI_STA_SAMPLE_SCANING,	  /* 1:扫描中 */
	WIFI_STA_SAMPLE_SCAN_DONE,	  /* 2:扫描完成 */
	WIFI_STA_SAMPLE_FOUND_TARGET, /* 3:匹配到目标AP */
	WIFI_STA_SAMPLE_CONNECTING,	  /* 4:连接中 */
	WIFI_STA_SAMPLE_CONNECT_DONE, /* 5:关联成功 */
	WIFI_STA_SAMPLE_GET_IP,		  /* 6:获取IP */
} wifi_state_enum;

static td_u8 g_wifi_state = WIFI_STA_SAMPLE_INIT;

/*****************************************************************************
  STA 扫描事件回调函数
*****************************************************************************/
static td_void wifi_scan_state_changed(td_s32 state, td_s32 size)
{
	UNUSED(state);
	UNUSED(size);
	osal_printk("%s::Scan done!.\r\n", CODE_LOG);
	g_wifi_state = WIFI_STA_SAMPLE_SCAN_DONE;
	return;
}

/*****************************************************************************
  STA 关联事件回调函数
*****************************************************************************/
static td_void wifi_connection_changed(td_s32 state, const wifi_linked_info_stru *info, td_s32 reason_code)
{
	UNUSED(info);
	UNUSED(reason_code);

	if (state == WIFI_NOT_AVALLIABLE)
	{
		osal_printk("%s Connect fail!. try agin !\r\n", CODE_LOG);

		// 发送连接断开事件
		if (g_wifi_sta_event_cb != NULL)
		{
			uint8_t connect_status = 0;
			g_wifi_sta_event_cb(WiFi_STA_EVENT_STATE_CHANGE, &connect_status, 1);
		}

		g_wifi_state = WIFI_STA_SAMPLE_INIT;

		// 创建WiFi连接处理任务
		osal_kthread_lock();
		osal_task *TaskHandle_WifiStaHandle = osal_kthread_create((osal_kthread_handler)wifi_sta_Handletask, 0, "WifiStaHandle_Task", 0x1000);
		if (TaskHandle_WifiStaHandle != NULL)
		{
			osal_kthread_set_priority(TaskHandle_WifiStaHandle, 15);
		}
		else
		{
			osal_printk("ERROR:%s Create WifiStaHandle_Task failed!\n", CODE_LOG);
		}
		osal_kthread_unlock();
	}
	else
	{
		osal_printk("%s Connect succ!.\r\n", CODE_LOG);
		g_wifi_state = WIFI_STA_SAMPLE_CONNECT_DONE;
	}
}

/*****************************************************************************
  STA 匹配目标AP
*****************************************************************************/
td_s32 example_get_match_network(wifi_sta_config_stru *expected_bss)
{
	td_s32 ret;
	td_u32 num = 64; /* 64:扫描到的Wi-Fi网络数量 */
	// td_char expected_ssid[] = "GEC_Test";
	// td_char key[] = "2233445566"; /* 待连接的网络接入密码 */
	td_bool find_ap = TD_FALSE;
	td_u8 bss_index;
	/* 获取扫描结果 */
	td_u32 scan_len = sizeof(wifi_scan_info_stru) * WIFI_SCAN_AP_LIMIT;
	wifi_scan_info_stru *result = osal_kmalloc(scan_len, OSAL_GFP_ATOMIC);
	if (result == TD_NULL)
	{
		return -1;
	}
	memset_s(result, scan_len, 0, scan_len);
	ret = wifi_sta_get_scan_info(result, &num);
	if (ret != 0)
	{
		osal_kfree(result);
		return -1;
	}
	/* 筛选扫描到的Wi-Fi网络，选择待连接的网络 */
	for (bss_index = 0; bss_index < num; bss_index++)
	{
		if (strlen(WiFi_Sta_SSID) == strlen(result[bss_index].ssid))
		{
			if (memcmp(WiFi_Sta_SSID, result[bss_index].ssid, strlen(WiFi_Sta_SSID)) == 0)
			{
				find_ap = TD_TRUE;
				break;
			}
		}
	}
	/* 未找到待连接AP,可以继续尝试扫描或者退出 */
	if (find_ap == TD_FALSE)
	{
		osal_kfree(result);
		return -1;
	}
	/* 找到网络后复制网络信息和接入密码 */
	if (memcpy_s(expected_bss->ssid, WIFI_MAX_SSID_LEN, WiFi_Sta_SSID, strlen(WiFi_Sta_SSID)) != 0)
	{
		osal_kfree(result);
		return -1;
	}
	if (memcpy_s(expected_bss->bssid, WIFI_MAC_LEN, result[bss_index].bssid, WIFI_MAC_LEN) != 0)
	{
		osal_kfree(result);
		return -1;
	}
	expected_bss->security_type = result[bss_index].security_type;
	if (memcpy_s(expected_bss->pre_shared_key, WIFI_MAX_SSID_LEN, WiFi_Sta_KEY, strlen(WiFi_Sta_KEY)) != 0)
	{
		osal_kfree(result);
		return -1;
	}
	expected_bss->ip_type = 1; /* 1：IP类型为动态DHCP获取 */
	osal_kfree(result);
	return 0;
}

/*****************************************************************************
  STA 关联状态查询
*****************************************************************************/
td_bool example_check_connect_status(td_void)
{
	td_u8 index;
	wifi_linked_info_stru wifi_status;
	/* 获取网络连接状态，共查询5次，每次间隔500ms */
	for (index = 0; index < 5; index++)
	{
		osal_msleep(500); /* 延时500ms */
		memset_s(&wifi_status, sizeof(wifi_linked_info_stru), 0, sizeof(wifi_linked_info_stru));
		if (wifi_sta_get_ap_info(&wifi_status) != 0)
		{
			continue;
		}
		if (wifi_status.conn_state == 1)
		{
			return 0; /* 连接成功退出循环 */
		}
	}
	return -1;
}

/*****************************************************************************
  STA DHCP状态查询
*****************************************************************************/
td_bool example_check_dhcp_status(struct netif *netif_p, td_u32 *wait_count)
{
	if ((ip_addr_isany(&(netif_p->ip_addr)) == 0) && (*wait_count <= WIFI_GET_IP_MAX_COUNT))
	{
		/* DHCP成功 */
		osal_printk("%s STA DHCP success.\r\n", CODE_LOG);
		return 0;
	}

	if (*wait_count > WIFI_GET_IP_MAX_COUNT)
	{
		osal_printk("%s STA DHCP timeout, try again !.\r\n", CODE_LOG);
		*wait_count = 0;
		g_wifi_state = WIFI_STA_SAMPLE_INIT;
	}
	return -1;
}

// wifi连接处理任务
void wifi_sta_Handletask(void *arg)
{
	td_char ifname[WIFI_IFNAME_MAX_SIZE + 1] = "wlan0"; /* 创建的STA接口名 */
	wifi_sta_config_stru expected_bss = {0};			/* 连接请求信息 */
	struct netif *netif_p = TD_NULL;
	td_u32 wait_count = 0;
	g_wifi_state = WIFI_STA_SAMPLE_INIT;

	do
	{
		osal_msleep(100); /* 等待10ms后判断状态 */
		if (g_wifi_state == WIFI_STA_SAMPLE_INIT)
		{
			osal_printk("%s Scan start!\r\n", CODE_LOG);
			g_wifi_state = WIFI_STA_SAMPLE_SCANING;
			/* 启动STA扫描 */
			if (wifi_sta_scan() != 0)
			{
				g_wifi_state = WIFI_STA_SAMPLE_INIT;
				continue;
			}
		}
		else if (g_wifi_state == WIFI_STA_SAMPLE_SCAN_DONE)
		{
			/* 获取待连接的网络 */
			if (example_get_match_network(&expected_bss) != 0)
			{
				osal_printk("%s Do not find AP, try again !\r\n", CODE_LOG);
				g_wifi_state = WIFI_STA_SAMPLE_INIT;
				continue;
			}
			g_wifi_state = WIFI_STA_SAMPLE_FOUND_TARGET;
		}
		else if (g_wifi_state == WIFI_STA_SAMPLE_FOUND_TARGET)
		{
			osal_printk("%s Connect start.\r\n", CODE_LOG);
			g_wifi_state = WIFI_STA_SAMPLE_CONNECTING;
			/* 启动连接 */
			if (wifi_sta_connect(&expected_bss) != 0)
			{
				g_wifi_state = WIFI_STA_SAMPLE_INIT;
				continue;
			}
		}
		else if (g_wifi_state == WIFI_STA_SAMPLE_CONNECT_DONE)
		{
			osal_printk("%s DHCP start.\r\n", CODE_LOG);
			g_wifi_state = WIFI_STA_SAMPLE_GET_IP;
			netif_p = netifapi_netif_find(ifname);
			if (netif_p == TD_NULL || netifapi_dhcp_start(netif_p) != 0)
			{
				osal_printk("%s find netif or start DHCP fail, try again !\r\n", CODE_LOG);
				g_wifi_state = WIFI_STA_SAMPLE_INIT;
				continue;
			}
		}
		else if (g_wifi_state == WIFI_STA_SAMPLE_GET_IP)
		{
			if (example_check_dhcp_status(netif_p, &wait_count) == 0)
			{
				// 发送连接成功事件
				if (g_wifi_sta_event_cb != NULL)
				{
					uint8_t connect_status = 1;
					g_wifi_sta_event_cb(WiFi_STA_EVENT_STATE_CHANGE, &connect_status, 1);
				}

				return;
			}
			wait_count++;
		}
	} while (1);
}

/* 设置wifi工作模式: STA模式，连接的AP参数在Kconfig中配置 */
td_s32 wifi_sta_init(char *ssid, char *password, wifi_sta_event_cb_t event_cb)
{
	osal_task *TaskHandle_WifiStaHandle = NULL; // WiFi连接任务句柄

	/* 初始化STA参数 */
	if (ssid == TD_NULL || password == TD_NULL)
	{
		return -1;
	}
	if (memcpy_s(WiFi_Sta_SSID, WIFI_MAX_SSID_LEN, ssid, strlen(ssid)) != 0)
	{
		return -1;
	}
	if (memcpy_s(WiFi_Sta_KEY, WIFI_MAX_KEY_LEN, password, strlen(password)) != 0)
	{
		return -1;
	}

	// 注册wifi-sta事件回调函数
	g_wifi_sta_event_cb = event_cb;

	/* 注册事件回调 */
	if (wifi_register_event_cb(&wifi_event_cb) != 0)
	{
		osal_printk("%s wifi_event_cb register fail.\r\n", CODE_LOG);
		return ERRCODE_FAIL;
	}
	// osal_printk("%s wifi_event_cb register succ.\r\n", CODE_LOG);

	/* 创建STA接口 */
	if (wifi_sta_enable() != 0)
	{
		return -1;
	}
	// osal_printk("%s STA enable succ.\r\n", CODE_LOG);

	// 创建WiFi连接处理任务
	osal_kthread_lock();
	TaskHandle_WifiStaHandle = osal_kthread_create((osal_kthread_handler)wifi_sta_Handletask, 0, "WifiStaHandle_Task", 0x1000);
	if (TaskHandle_WifiStaHandle != NULL)
	{
		osal_kthread_set_priority(TaskHandle_WifiStaHandle, 15);
	}
	else
	{
		osal_printk("ERROR:%s Create WifiStaHandle_Task failed!\n", CODE_LOG);
	}
	osal_kthread_unlock();

	return 0;
}